<template>
  <component :is="tag" ref="draggable_wrapper" class="default_vue_module">
    <slot />
  </component>
</template>

<script lang="ts">
import Vue, { ComponentInstance } from 'vue'
import { Component, Prop, Watch } from 'vue-property-decorator'
import Sortable from 'sortablejs'
import { Dictionary } from 'vue-router/types/router'
interface MyWindow extends Window {
  __WsTableDraggableContext?: Map<HTMLElement, ComponentInstance>
}
const WRAPPER = '.el-table__body-wrapper tbody'
@Component
class WsTableDraggable extends Vue {
  @Prop({ default: 'div' }) tag!: string
  @Prop({ required: true }) wrapperKey!: string | number | symbol
  myWindow: MyWindow = window
  table: HTMLElement | null = null
  _sortableClass: Sortable | null = null
  @Watch('$attrs', { deep: true })
  attrs_handler(options: Dictionary<any>) {
    const { _sortableClass } = this
    if (_sortableClass) {
      const filterKeys = Object.keys(options).filter(key => key.indexOf('on') !== 0)
      filterKeys.forEach(key => {
        _sortableClass.option(key as keyof Sortable.Options, options[key])
      })
    }
  }
  mounted() {
    if (!this.myWindow.__WsTableDraggableContext) {
      this.myWindow.__WsTableDraggableContext = new Map()
    }
    this.init()
  }
  init() {
    const context = this.myWindow.__WsTableDraggableContext
    if (!context) {
      throw new Error('Draggable table is not existed')
    }
    if (!this.$children[0] && !(this.$children[0] as ComponentInstance).$el) {
      throw new Error('No user-supplied elements was found in the default slot')
    }
    this.destroy()
    this.table = this.$children[0].$el.querySelector(WRAPPER) as HTMLElement
    const elTableContext = this.$children[0]
    context.set(this.table, elTableContext)
    const _this = this
    this._sortableClass = new Sortable(this.table, {
      ..._this.$attrs,
      ...Object.keys(_this.$listeners).reduce((events: Dictionary<any>, key) => {
        const handler = _this.$listeners[key] as (...rest: any[]) => void
        events[key] = (...args: any[]) => handler(...args)
        return events
      }, {})
    })
  }
  destroy() {
    if (this._sortableClass) {
      this._sortableClass.destroy()
      this._sortableClass = null
    }
    const context = this.myWindow.__WsTableDraggableContext
    if (context && this.table && context.has(this.table)) {
      context.delete(this.table)
    }
    this.table = null
  }
}
export default WsTableDraggable
</script>

<style lang="less" scoped></style>
